package parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import model.ParsedPage;
import model.ParsedProduct;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import crawler.DomainCrawler;

/**
 * Poate parsa deocamdata doar siturile care au pretul intr-un element din grupa price.
 * Obtine toate linkurile relevante sau nu.
 * Cuvintele le obtine din meta-ul description sau keywords in functie de potrivirea lor in textul din body.
 * Merge pe emag. altex, mediagalaxy, flanco.
 * 
 * @author octav
 *
 */
public class HtmlParser extends Thread {
	
	private String url;
	private DomainCrawler domainCrawler;
	
	public HtmlParser(String url, DomainCrawler domainCrawler) {
		this.url = url;
		this.domainCrawler = domainCrawler;
		start();
	}
	
	@Override
	public void run() {
		Document document;
		ParsedPage parsedPage = null;
		try {
			
			boolean ok = false;
			while (!ok) {
				synchronized (this.domainCrawler) {
					ok = this.domainCrawler.registerThread();
				}
				if (!ok) Thread.sleep(1000);
			}
			
			// Get html page
			document = Jsoup.connect(url).get();
			String description[] = null;
			float price = 0;
			
			// Gets all the links except the current one
			String[] urls = this.parseUrls(document);
			
			ParsedProduct parsedProduct = new ParsedProduct();
			String meta = null;
			// Obtains the price for the current product
			price = parsePrice(document);
			if(price != 0){				
				// Obtains the description for the product
				meta = parseDescription(document);
				description = meta.split(" ");
				
				// Creates the return element
				parsedProduct = new ParsedProduct(description, price);
			}			
			if (parsedProduct.getPrice() > 0 && meta != null)
				parsedPage = new ParsedPage(parsedProduct, urls, new Date(), url, meta);
			else
				parsedPage = new ParsedPage(null, urls, new Date(), url, meta);
			
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			synchronized (this.domainCrawler) {
				if (parsedPage != null) {
					this.domainCrawler.addParsedPage(parsedPage);
				}
				this.domainCrawler.unregisterThread();
			}
		}
		
	}
	
	/**
	 * Extracts all the urls in the HTML page and stores their absolute value.
	 * @param document - HTML document
	 * @return An array with all the urls
	 */
	private String[] parseUrls(Document document) {
		List<String> urls = new ArrayList<String>();
		for (Element element : document.select("a")) {
			String aux = element.attr("abs:href");
			if (!aux.equals(this.url)) 
				urls.add(aux);
		}
		return urls.toArray(new String[0]);
	}
	
	/**
	 * Tries to find a price tag in the HTML document
	 * @param document - HTML document
	 * @return A float representing the price
	 */
	private Float parsePrice(Document document) {
		Element element = document.select(".price").first();
		Float price = 0.0f;
		if(element != null){
			String priceString = element.text().toLowerCase().replace(".", "").replace(',', '.');
			Matcher matcher = Pattern.compile("[1-9][0-9]*.[0-9]+").matcher(priceString);
			matcher.find();
			price = Float.parseFloat(matcher.group(0));
		}else{
			System.out.println("doc null in html parser");			
		}
		return price;
	}	
	
	/**
	 * Identifies and returns the essential description keywords from the meta
	 * @param document - HTML document
	 * @return An array on keywords
	 */
	private String parseDescription(Document document) {
		
		String metaDescriprion = document.select("meta[name=description]").first().attr("content");
		String metaKeywords = document.select("meta[name=keywords]").first().attr("content");
		
		if (document.body().text().indexOf(metaDescriprion.substring(0, metaDescriprion.length() / 4)) > -1) {
			return metaDescriprion;
		}
		else if (document.body().text().indexOf(metaKeywords.substring(0, metaDescriprion.length() / 4)) > -1) {
			return metaKeywords;
		}
		
		return null;
	}

}
